Gustavo Jacoinde's profile

Flutter: Aplicación no oficial de SpaceX API

Flutter: Aplicación no oficial de SpaceX API
Descripción

Desarrolló: ​​​​​​​Jacoinde Argüello Gustavo
Framework: Flutter
Lenguaje de programación: DART
Open Source REST API: https://github.com/r-spacex/SpaceX-API?tab=readme-ov-file
Técnica: Programación orientada a widgets o programación orientada a componentes . 
Paradigma: Programación orientada a objetos.
Entorno de Desarrollo I
ntegrado(IDE): VSCODE
Sistema Operativo: Fedora Linux.
Esta API REST de código abierto permite obtener los recursos y los datos que están expuestos para su acceso y manipulación. Aunque los creadores de esta API  nos advierten en su repositorio  de GITHUB  que ellos: No están afiliados, asociados, autorizados, respaldados ni conectados oficialmente de ninguna manera con Space Exploration Technologies Corp (SpaceX).
Esta interfaz está diseñada para ser simple, escalable y flexible, permitiendo la interoperabilidad entre sistemas distribuidos de manera eficiente.

“We are not affiliated, associated, authorized, endorsed by, or in any way officially connected with Space Exploration Technologies Corp (SpaceX), or any of its subsidiaries or its affiliates. The names SpaceX as well as related names, marks, emblems and images are registered trademarks of their respective owners.” 
Fuente:r-spacex/ SpaceX-API

También nos proporciona la siguiente información sobre:  
Autenticación:
No se requiere autenticación para utilizar esta API.
Privacidad: No se registran direcciones IP ni ninguna información de identificación personal a nivel de aplicación o servidor web. Se recopilan marcas de tiempo, métodos HTTP, URL y tiempos de respuesta para ajustar las estrategias de almacenamiento en caché en puntos finales populares.
Limitación de tasa: La API tiene un límite de velocidad de 50 solicitudes/seg por dirección IP; si se excede, se dará una respuesta de 429 hasta que la velocidad vuelva a caer por debajo de 50 solicitudes/seg.
Almacenamiento en caché: En general, los tiempos de caché estándar son los siguientes:
launches - 30 seconds
ships, payloads, roadster - 5 minutes
capsules, cores, launchpads, landpads - 1 hour
dragons, rockets, missions, history, company info - 24 hours

La API está disponible sólo para lectura, lo que significa que solo podemos acceder a los recursos utilizando el método GET. Por lo tanto, podemos utilizar la siguiente interfaz para acceder a todos los recursos:
GET /recursos: Recupera una lista de todos los recursos.
GET /recurso/{id}: Recupera los detalles de un recurso en específico.
Cada endpoint y método define una operación específica que se puede realizar en los recursos de la API. La interfaz también puede incluir parámetros adicionales en las URLs para filtrar, ordenar o paginar los resultados, dependiendo de los requisitos específicos de la aplicación.
Ejemplo de Endpoint: https://api.spacexdata.com/v4/crew
Este endpoint devuelve la lista de astronautas que han participado en misiones con SpaceX. La respuesta del endpoint es un arreglo de objetos donde cada objeto contiene propiedades que ofrecen información específica acerca de cada astronauta:
Para una gestión efectiva de la información dentro de la aplicación, es crucial comprender la estructura de datos devuelta por el endpoint de la API REST. Esto implica la necesidad de crear un modelo que se ajuste a los tipos de datos específicos obtenidos como respuesta del endpoint.

Lista de recursos:
Al momento de escribir este documento nos indican que la versión 3 de la API está depreciada y nos recomiendan usar la versión 4.
Vista de Presentación(Home)
Clase GetCompanyHome
En esta clase, utilizo un widget que muestra una imagen de fondo con ancho y alto completos utilizando la propiedad double.infinity dentro de un contenedor limitado por un SizedBox. La imagen se carga desde una URL utilizando Image.network y se ajusta para cubrir todo el contenedor con la propiedad BoxFit.cover.
Desarrollo del modelo y la vista Astronautas
En la clase StarmanCrewModel creó un ​​​​​​​modelo de datos que representa las propiedades de los miembros del equipo de Astronautas. Este modelo tiene cinco propiedades que corresponden a diferentes aspectos de un miembro del equipo de Astronautas:
1. name: El nombre del miembro del equipo.
2. agency: La agencia a la que pertenece el miembro del equipo.
3. image: La URL de la imagen del miembro del equipo.
4. status: El estado actual del miembro del equipo .
5. id: El identificador único del miembro del equipo.

El constructor StarmanCrewModel nos permite crear instancias de esta clase con valores opcionales para cada una de las propiedades.

¿Por qué se deben manejar los valores opcionales en los modelos?

Al marcar las propiedades con String?, estamos indicando que esas propiedades pueden contener valores nulos además de sus tipos de datos regulares. Esto significa que al crear una instancia de StarmanCrewModel, no es obligatorio proporcionar valores para estas propiedades. Podemos pasar null o simplemente no proporcionar un valor, lo que hace que esas propiedades tengan un valor predeterminado de null

Este enfoque es útil cuando trabajamos con datos que pueden o no estar presentes o que podrían no tener valores definidos en ciertas situaciones.

Trabajar con valores opcionales nos permite crear instancias de la clase incluso si no tenemos todos los datos disponibles en un momento dado, lo que brinda flexibilidad al trabajar con objetos de este tipo en nuestro código.


Ahora, relacionando esta clase con la respuesta del endpoint, utilizaremos esta clase para mapear los datos devueltos por el endpoint a objetos concretos en la aplicación. 
Por ejemplo, si el endpoint devuelve datos sobre astronautas, podemos crear instancias de StarmanCrewModel para cada astronauta utilizando los datos proporcionados por el endpoint. Esto nos permite estructurar y gestionar la información de manera efectiva dentro de nuestra aplicación, ya que podemos acceder y manipular los datos de cada miembro del equipo de astronautas de manera coherente y estructurada.
Diseñando la interfaz del widget para la sección de los astronautas y  los lanzamientos de cohetes.
Widget: XstaggeredGrid.
Tipo: Reutilizable
Técnica: Programación orientada a componentes. 
Manejador de estado: StatefulWidget & ChangeNotifierProvider.
He desarrollado un Widget reutilizable que brinda una experiencia dinámica al mostrar imágenes de astronautas y lanzamientos de cohetes en una cuadrícula diseñada específicamente para vistas que incluyan elementos gráficos.

Este Widget ofrece una forma atractiva y eficiente de presentar información visual en la aplicación, proporcionando una experiencia agradable y efectiva para los usuarios.

El Widget está diseñado para ser altamente personalizable, lo que significa que podemos ajustar fácilmente el diseño de la cuadrícula, el tamaño de las imágenes y otros aspectos visuales para que se adapten a las necesidades específicas de la aplicación. Además, su implementación como Widget reutilizable facilita su integración en diferentes partes de la aplicación, manteniendo una coherencia visual en toda la interfaz de usuario.

El elemento central de esta interfaz de usuario es el widget flutter_staggered_grid_view, el cual ofrece una amplia variedad de diseños de cuadrículas para organizar y mostrar contenido de forma dinámica y atractiva.

flutter_staggered_grid_view Fuente: https://pub.dev/packages/flutter_staggered_grid_view/install
Definición de las clases que integran el Widget XstaggeredGrid.
I. Clase XstaggeredGrid
He creado esta clase pública para que pueda ser accesible accesible desde cualquier parte del código en nuestra aplicación. Además, es responsable de proporcionar información a las clases descendientes mediante su inicialización, suministrando los valores según sean requeridos. Está diseñada con un total de siete parámetros, de los cuales cuatro son opcionales, tres son requeridos y un super.key.
Para los parámetros opcionales no es necesario proporcionar valores al crear la instancia de la clase; sin embargo, podemos proporcionar valores específicos si lo deseamos cuando llamamos al constructor. Si no se proporcionan valores, se usarán los valores predeterminados que hemos establecido en el constructor.

Cuando trabajamos con parámetros opcionales en una clase, no es obligatorio proporcionar valores al crear una instancia de la misma. Esto significa que podemos crear objetos de la clase sin especificar estos parámetros. Sin embargo, tenemos la flexibilidad de proporcionar valores específicos cuando llamamos al constructor si así lo deseamos. En caso de no proporcionar valores, la clase utilizará los valores predeterminados que hemos establecido en el constructor para estos parámetros opcionales.

Opcionales:
1. tileNumbers
2. width
3. height
4. index. 
Requeridos:
1. idModelProperty
2. imagemodelProperty
3. entityName
Por otro lado, para los parámetros requeridos es fundamental asignarles un valor al crear una instancia de la clase. Estos parámetros son esenciales para el funcionamiento adecuado de la instancia y su comportamiento dentro del programa. Si no se asigna un valor a un parámetro requerido al momento de crear la instancia, el programa generará un error ya que no podrá completar la inicialización necesaria para el objeto.

En resumen, La clase XstaggeredGrid que creé y describí es un widget en Flutter que utilizó para representar y mostrar elementos en un diseño de cuadrícula escalonada (staggered grid). Este tipo de diseño es útil cuando se desea mostrar elementos de diferentes tamaños en una cuadrícula, donde cada elemento puede ocupar un espacio diferente en función de sus propiedades.

Algunos casos comunes de uso para crear un widget de cuadrícula escalonada como nuestra clase XstaggeredGrid podrían incluir:

Galería de imágenes: Mostrar una colección de imágenes de diferentes tamaños y proporciones en una cuadrícula escalonada.
Mosaico de publicaciones: Mostrar publicaciones o tarjetas de contenido donde cada tarjeta puede tener un tamaño diferente en función de su contenido.
Parrilla de elementos de diseño personalizado: Crear una interfaz de usuario que muestre elementos (como widgets personalizados) en una cuadrícula donde el tamaño de cada elemento pueda variar dinámicamente.
Diseños de tablero de instrumentos: Mostrar datos y widgets en un tablero de instrumentos donde la disposición de los elementos depende de factores como su importancia o tamaño.


¿Qué es el parámetro super.key?

El parámetro super.key que está definido en el código anterior se refiere al parámetro que se hereda de la clase padre StatelessWidget o StatefulWidget. En Flutter, muchos widgets se heredan de estas clases base para crear componentes de la interfaz de usuario.

El parámetro super.key se utiliza para identificar de manera única un widget dentro del árbol de widgets de Flutter. Esto es útil cuando necesitamos realizar operaciones específicas con un widget en particular, como actualizarlo, moverlo o eliminarlo del árbol de widgets. La clave (key) ayuda a Flutter a diferenciar entre diferentes widgets que podrían tener la misma apariencia y comportamiento pero que son entidades distintas en el árbol de widgets.

Al llamar a super.key, estamos pasando el parámetro key de la clase padre al constructor de la clase actual. Esto es comúnmente utilizado en Flutter para permitir que los widgets que se construyen a partir de clases base como StatelessWidget o StatefulWidget también puedan tener una clave (key) asignada, lo que facilita su identificación y manipulación en el árbol de widgets.​​​​​​​
II. Clase _MasonryGridView
Además de construir la cuadrícula (flutter_staggered_grid_view) para organizar y mostrar dinámicamente las imágenes de los astronautas y los lanzamientos de cohetes, esta clase también gestiona un indicador de carga que se desactiva una vez que se han cargado los datos. Este indicador vuelve a activarse automáticamente cuando el usuario realiza un desplazamiento vertical hacia arriba o hacia abajo para obtener más datos, asegurando una experiencia fluida y orientada a la carga progresiva de información.
Indicador de carga
He definido la clase _MasonryGridView como privada, lo cual significa que solo puede ser accedida desde dentro del archivo en el que está definida. Esto ayuda a encapsular la implementación y limita su uso sólo a las partes del código que están dentro del mismo archivo.

Al definir una clase privada, estamos aplicando el concepto de encapsulamiento del paradigma de programación orientada a objetos (OOP). El encapsulamiento es uno de los pilares fundamentales de la OOP y se refiere a la ocultación de los detalles internos de un objeto y la exposición solo de la interfaz necesaria para interactuar con él. Por otro lado, la clase también extiende o hereda todas las características y funcionalidades específicas de un StatefulWidget.

El motivo de heredar las funcionalidades del StatefulWidget en esta clase es para poder implementar el indicador de carga mencionado anteriormente ya que en Flutter, un StatefulWidget es un widget que tiene un estado mutable. Esto significa que puede cambiar su apariencia y comportamiento durante el ciclo de vida de la aplicación.

Al extender con StatefulWidget, la clase _MasonryGridView puede contener un estado interno (State) que puede modificarse, por ejemplo, para actualizar la vista cuando cambian los datos o cuando se produce una interacción del usuario.
El estado interno se maneja mediante una clase separada que extiende con State, lo que permite separar la lógica del widget de su representación visual.
El ejemplo del código anterior es una implementación de un estado (State) en Flutter
Más específicamente, es el estado del widget llamado _MasonryGridView encargado de retornar el  widget que contiene la estructura de la cuadrícula en la que se muestran las imágenes de los astronautas y los lanzamientos de cohetes, pero antes debemos asegurarnos de que los datos han sido cargados mendiante la clase _MasonryGridViewState la cual crea un estado para el widget _MasonryGridView, inicializa un ScrollController para controlar el desplazamiento de la vista en el indicador de carga, gestiona el estado de carga (_isLoading), realiza tareas de inicialización en initState, y libera recursos con el método dispose cuando el estado se desecha para evitar fugas de memoria y problemas de rendimiento.
Cuando  _isLoading es verdadero la clase _MasonryGridView retorna el  widget que contiene la estructura de la cuadrícula.
III. Clase _ClippRectStaggeredGrid

Mediante la técnica Programación orientada a componentes descrita al inicio del documento hago referencia a la clase privada _ClippRectStaggeredGrid la cual tiene dos funciones: 
1. Implementar el borde redondeado a las imágenes mediante el widget ClipRRect y su propiedad borderRadius.
2. Referenciar a la clase _ImageStaggeredGrid mediante su propiedad child

IV. Clase _ImageStaggeredGrid

He implementado el widget Image.network dentro de la clase privada _ImageStaggeredGrid para mostrar imágenes cargadas desde URLs específicas. Estas URLs son obtenidas a través de la propiedad imagemodelProperty de nuestros modelos, los cuales están emparejados con la respuesta de la API
1. height
2. index
3. idModelProperty
4. imagemodelProperty
5. entityName

height: Ajusta el tamaño de la imagen dentro de la cuadrícula en la interfaz de usuario según la altura deseada.
index: Representa el índice del elemento en la cuadrícula de imágenes. Los índices son útiles para identificar y diferenciar elementos dentro de una lista o cuadrícula. Pueden usarse para acceder a datos específicos asociados con el elemento en esa posición.
List<String>idModelProperty: Este parámetro  Contiene los ID del modelo o  entidad dependiendo la vista( Astronautas o lanzamientos ) elegida por el usuario. 
List<String> imagemodelProperty: Este parámetro  Contiene las URL de las imágenes relacionadas a la entidad dependiendo la vista( Astronautas o lanzamientos ) elegida por el usuario.
dynamic entityName: Este parámetro  contiene el nombre del modelo dependiendo la vista( Astronautas o lanzamientos ) elegida por el usuario.
Propiedades de los modelos StarmanCrewModel(Astronautas) y ModelLaunches(Lanzamientos).
Propiedades de los modelos StarmanCrewModel(Astronautas) y ModelLaunches(Lanzamientos).
Otra característica importante asignada a la clase _ImageStaggeredGrid es su capacidad para proporcionar la lógica necesaria para vincularse con la vista detallada de los astronautas o los lanzamientos de cohetes, tal como se muestra a continuación.
Para enriquecer la experiencia del usuario, aproveché la información proporcionada por la API en el detalle de los lanzamientos para implementar un reproductor de video. Este reproductor muestra videos de todos los lanzamientos de las distintas misiones espaciales utilizando las URLs proporcionadas por la misma API. De esta manera, los usuarios pueden visualizar de forma dinámica y directa los momentos clave de cada misión espacial, brindando una perspectiva más completa de la información disponible.
Resultado del detalle en video de las misiones 
El código anterior muestra como la clase _ImageStaggeredGrid retorna  el widget GestureDetector el cual se encarga de implementar la función del manejador de eventos onTap en Flutter. En esta implementación utilizó el patrón Provider en conjunto con el widget de navegación entre pantallas llamado MaterialPageRoute.

onTap: Este evento se activa cuando el usuario toca el widget al que se le ha asignado esta función. En este caso, está asociado al widget Image.network dentro de un elemento de lista.
provider: Aquí utilizo el patrón Provider para acceder a la instancia de UImodelStaggeredGrid y llamar a su método setFunctionButton.

navigator: Dentro de la función asignada al evento onTap, utilizó la propiedad Navigator.push para navegar a una nueva vista cuando el evento onTap se dispara.

materialPageRoute: Aquí implemento una nueva instancia de MaterialPageRoute para definir la ruta de navegación hacia la pantalla GetStarManCrewID o GetLaunchesID, la cual es la vista de detalles del astronauta o del lanzamiento respectivamente. Esta ruta se construye mediante el builder, que recibe el contexto y devuelve la nueva vista con la información del astronauta o el lanzamiento seleccionado por el usuario.

Instanciando y utilizando nuestra clase XstaggeredGrid con
 Business Logic Component (BLoC)



Clase GetStarMan​​​​​​​
En esta clase utilizó los paquetes Flutter BLoC y Provider para implementar una arquitectura basada en BLoC (Business Logic Component) y el patrón de diseño de Provider.
Además, en esta clase implementó una solicitud asíncrona utilizando BLoC para obtener información del servicio (StarManCrewService), el cual se encarga de realizar la llamada a la API y devolver los resultados correspondientes

Basándose en la respuesta de la solicitud asíncrona, la clase escucha los cambios en el estado y reconstruye su widget hijo según corresponda al estado actual. Esto permite mostrar diferentes widgets dependiendo del estado:

1. Cuando el estado es loading: Se muestra un indicador de progreso.
2. Cuando el estado es success:  
Se muestra el widget con los datos obtenidos del estado.
3. Cuando el estado es error:
se muestra un widget de texto con el mensaje "no hay datos disponibles.


Cuando separamos la lógica de negocio utilizando Provider y BLoC logramos una gestión más clara y estructurada del estado y la lógica de la aplicación.
Es en este punto, cuando los datos que obtenemos de la respuesta en la API, ya deben estar emparejados y organizados con el modelo StarmanCrewModel o ModelLaunches  de manera coherente. Esta relación entre la respuesta de la API y los modelos asegura que los datos obtenidos se muestran correctamente en la interfaz de usuario de acuerdo con la estructura y el formato esperado. De esta manera, logramos una presentación consistente y efectiva de la información en nuestra aplicación.
Diseñando la interfaz del widget para la sección de los cohetes y las naves espaciales

Widget: XCardWidget.
Tipo:
Reutilizable.
Técnica:
Programación orientada a componentes. 

Este Widget reutilizable es una herramienta fundamental para mostrar información detallada sobre las cápsulas Dragón y los cohetes Falcon en nuestra aplicación. Para gestionar y navegar por estos elementos, implementamos el widget SingleChildScrollView, que permite desplazarnos verticalmente en ambas direcciones. Además, para mejorar la presentación visual de las imágenes, personalizamos el widget Card, proporcionando un formato atractivo y coherente para cada elemento mostrado.
El antes y el después de personalizar el widget card
En este widget, al igual que en el anterior, realizamos llamadas a la API para obtener las imágenes y la información necesaria sobre las naves espaciales, las cuales están emparejadas y organizadas con los modelos correspondientes a cada tipo de nave o cohete. Además, para garantizar una gestión eficiente y estructurada del estado y la lógica de la aplicación, he separado la lógica de negocio utilizando Provider y BLoC. Esta separación nos permite tener un código más organizado y facilita la implementación de funcionalidades adicionales, manteniendo la claridad y la coherencia en el flujo de datos y la presentación de la información en la interfaz de usuario.
Resultado final XCardWidget
Accediendo al detalle de cada Nave 

Para el detalle de cada nave, he desarrollado un Slider de imágenes que recibe todas las imágenes relacionadas con la nave seleccionada por el usuario. Este Slider también es reutilizable dentro del detalle de cada nave. En la parte superior del detalle, he incluido un banner animado que muestra el tipo de propulsores y el tipo de combustible de cada nave. Además, en la sección central, agregué un DataTable que muestra características detalladas de la nave seleccionada, y finalmente, se incluye una descripción textual completa de la nave para brindar información adicional al usuario.
Flutter: Aplicación no oficial de SpaceX API
Published:

Flutter: Aplicación no oficial de SpaceX API

Published: